﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;

using Debug = System.Diagnostics.Debug;

namespace Piao
{
    public enum SigninMode
    {
        ResumeFromLastGood,
        NewSign,
    }

    public partial class MainForm : Form
    {
        [DllImport("user32")]
        public static extern bool SetForegroundWindow(IntPtr handle);
        [DllImport("User32.dll")]
        public static extern IntPtr FindWindow(string className, string windowName);
        [DllImport("User32.dll")]
        public static extern bool IsWindow(IntPtr hwnd);
        public const uint WM_CLOSE = 0x0010;

        [DllImport("user32.dll")]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);
        public delegate bool EnumDesktopWindowsDelegate(IntPtr hWnd, int lParam);
        [DllImport("user32.dll", EntryPoint = "EnumDesktopWindows")]
        public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDesktopWindowsDelegate lpEnumCallbackFunction, IntPtr lParam);


        public const string FORM_UNIQUE_Name = "12306RailTicketWndClass";
        public delegate void UpdateFormControlDelegate(object arg);

        Func<Image, string> captchaHandle;//initialized in ctor.
        private static Mutex threadMutex = new Mutex(false, "{69082C9C-0783-41B8-BC32-BD5556F10D09}");
        private List<UserData> passengers = new List<UserData>() { };

        SigninMode signinMode = SigninMode.ResumeFromLastGood;
        DateTime lastPress = DateTime.Today;
        string pressed = string.Empty;

        int WORKER_TIMEOUT_MINUTES = 60;
        int ORDER_DAY_AHEAD = Configurations.Instance.DaysAhead;
        Win7ProcessIcon win7SuperIcon = new Win7ProcessIcon();
        ListenerWindow listen = null;

        private Thread mainWorkThread = null;

        private static MainForm internalInstance = null;
        public static MainForm Instance
        {
            get
            {
                if (internalInstance == null || internalInstance.IsDisposed)
                {
                    internalInstance = null;
                    internalInstance = new MainForm();
                }
                return internalInstance;
            }
        }

        public MainForm()
        {
            InitializeComponent();
            InitializeComponentDataBinding();

            InitializeControlsFromSetting();
            InitializeCaptchaDelegate();

            //close and reopen case click signin without captcha
            //support re-singin, when window is closed, resume from last session
            UserOpration.Instance.InitPreviousCookie();
            this.HandleCreated += (object sender, EventArgs e) =>
            {
                btn_login_Click(btn_login, EventArgs.Empty);
            };

#if DEBUG
            System.Diagnostics.Debugger.Launch();
            this.Text += " - DEBUG VERSION";
            menu_start.Enabled = true;
#endif

        }



        private void txt_userFromStation_Autocompletion(object sender, KeyPressEventArgs e)
        {
            ComboBox box = (sender as ComboBox);
            BindingSource filterSource = box.DataSource as BindingSource;
            if (filterSource == null)
                return;

            //reset all columns
            if (e.KeyChar == (char)Keys.Escape)
            {
                if (box.SelectedIndex > 0)
                {
                    string text = box.Text;
                    filterSource.Filter = string.Empty;
                    box.Text = text;
                }
                else
                    filterSource.Filter = string.Empty;

                e.Handled = true;

                return;
            }

            //only accept valid input [a-zA-Z]
            //65-90 97-122

            bool onlyLetters = (e.KeyChar >= (char)65 && e.KeyChar <= (char)90) || (e.KeyChar >= (char)97 && e.KeyChar <= (char)122);
            if (!onlyLetters)
                return;

            //timeout to clear cached input
            TimeSpan ts = DateTime.Now - lastPress;
            if (ts.TotalSeconds > 1)
            {
                pressed = string.Empty;
            }

            lastPress = DateTime.Now;
            pressed += e.KeyChar.ToString().ToUpper();

            //dont use empty data source , the combox will throw ArgumentOutofRangeException
            //before that there is an empty row added in the table, it will be default item when search has no result
            string searchQuery = string.Format("[{0}] like '{1}%'", Global.DataComlumnPinYin, pressed);
            if (Global.StationNameTable.Select(searchQuery).Length == 0)
                searchQuery = string.Format("[{0}] is null", Global.DataComlumnPinYin);

            Log.Debug("filter by {0}", searchQuery);
            filterSource.Filter = searchQuery;

            //only handle the first char for navigation
            if (pressed.Length != 1)
                e.Handled = true;

            Debug.WriteLine(pressed);
        }

        private void txt_webCaptcha_KeyPressForFilter(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Back || e.KeyChar == (char)Keys.Delete)
                return;

            if (e.KeyChar >= 'a' && e.KeyChar <= 'z')
                e.KeyChar = (char)((int)e.KeyChar - 32);

            if (txt_webCaptcha.Text.Length >= 4)
            {
                e.Handled = true;
                return;
            }

            if ((e.KeyChar >= '0' && e.KeyChar <= '9')
                || (e.KeyChar >= 'A' && e.KeyChar <= 'Z')
                || (e.KeyChar == ' ')
                )
            {
                //Log.Debug("valid input {0}", (Keys)e.KeyChar);
            }
            else
                e.Handled = true;
        }

        /// <summary>
        /// read server city names.
        /// </summary>
        private void StartPrep()
        {
            Log.Debug("start:after logon init.");
            UpdateFormControlDelegate initialzeStationThreadDelegate = new UpdateFormControlDelegate(arg =>
            {
                if (Global.StationNameDict.Count == 0)
                {
                    MessageBox.Show("未能初始化，关闭并重启窗口再试。", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                try
                {
                    //here assign data source only once
                    if (txt_userFromStation.DataSource == null)
                    {
                        Log.Debug("apply data source to controls");
                        BindingSource bindSourceFrom = new BindingSource();
                        BindingSource bindSourceTo = new BindingSource();

                        //use different data source
                        bindSourceFrom.DataSource = Global.StationNameTable;
                        bindSourceTo.DataSource = Global.StationNameTable.Copy();

                        txt_userFromStation.DataSource = bindSourceFrom;
                        txt_userFromStation.ValueMember = Global.DataComlumnDisplayText;

                        txt_userToStation.DataSource = bindSourceTo;
                        txt_userToStation.ValueMember = Global.DataComlumnDisplayText;
                    }

                    txt_userFromStation.Enabled = true;
                    txt_userToStation.Enabled = true;
                    txt_userFromStation.Text = Configurations.Instance.txt_userFromStation;
                    txt_userToStation.Text = Configurations.Instance.txt_userToStation;
                }
                catch (Exception exc)
                {
                    Log.Debug(exc.ToString());
                }

            });


            UpdateFormControlDelegate initialzeSeatTypesThreadDelegate = new UpdateFormControlDelegate(arg =>
                {
                    Log.Debug("refresh seat types.");
                    List<JsonObject> list = arg as List<JsonObject>;
                    if (list == null || list.Count == 0)
                        return;


                    try
                    {
                        foreach (JsonObject obj in list)
                        {
                            if (chk_userSeatTypes.Items.Contains(obj.value) == false)
                            {
                                chk_userSeatTypes.Items.Add(obj.value);
                            }
                        }

                        if (chk_userSeatTypes.Items.Count > 2)
                        {
                            chk_userSeatTypes.SetItemChecked(0, true);
                            chk_userSeatTypes.SetItemChecked(1, true);
                        }
                        Log.Debug("end:select first seat as default.");

                        txt_userToStation_QueryStStrainAll(txt_userToStation, EventArgs.Empty);
                    }
                    catch (Exception exc)
                    {
                        Log.Debug(exc.ToString());
                    }
                });


            UpdateFormControlDelegate initialzeControlDisplayThreadDelegate = new UpdateFormControlDelegate(arg =>
                {
                    Log.Debug("end:app init is complete.");
                    menu_status.Text = "Ready";
                    group_captcha.Enabled = true;
                    group_login.Enabled = true;
                    group_ticket.Enabled = true;
                    group_webform.Enabled = true;
                });


            Thread thPrep = new Thread(() =>
            {
                int i = 0;
                while (i++ < 2)
                {
                    if (Global.StationNameDict.Count == 0)
                        UserOpration.Instance.QueryStationName();
                    else if (Global.TicketCodeList.Count == 0)
                        UserOpration.Instance.QuerySeatTypes();
                    else
                        break;

                    CheckThreadStateToAbort();
                    Thread.Sleep(1000);
                }

                if (!this.IsDisposed)
                {
                    this.Invoke(initialzeStationThreadDelegate, Global.StationNameDict);
                    this.Invoke(initialzeSeatTypesThreadDelegate, Global.TicketCodeList);
                    this.Invoke(initialzeControlDisplayThreadDelegate, "");
                }

            });

            thPrep.Start();
        }

        private void btn_login_Click(object sender, EventArgs e)
        {
            Log.Debug("start:log in");
            this.btn_login.Enabled = false;
            group_login.Visible = false;
            txt_webCaptcha.Focus();
            string user = txt_userWebName.Text;
            string pwd = txt_userWebPassword.Text;


            UpdateFormControlDelegate loginComplete = new UpdateFormControlDelegate(arg =>
            {
                string welcomename = arg as string;
                user_imageBox.Image = null;
                lbl_userCaptchaInfo.Text = string.Empty;
                txt_webCaptcha.Text = null;
                btn_login.Enabled = true;
                btn_login.Focus();

                if (!string.IsNullOrEmpty(welcomename))
                {
                    ShowToolTip("Log in", "登陆成功");
                    this.Text = arg.ToString();
                    menu_status.Text = "登陆成功";
                    txt_webCaptcha.Focus(); //set this object with keyboard focus in case press error
                    menu_start.ForeColor = Color.Red;
                    menu_start.Enabled = true;
                    StartPrep();
                    group_login.Visible = false;
                    Log.Message("已登陆， 等待加载成功后点击 {0} 刷新； 站名首字母查询不支持多音字。", menu_start.Text);
                    Log.Message("刷新页面即同步登陆。");
                }
                else
                {
                    ShowToolTip("Log in", "登陆失败。");
                    group_login.Visible = true;
                }

                Log.Debug("log in action is complete.");
            });


            Thread waitInputThread = new Thread(() =>
            {
                string propmtString = string.Empty;
                if (signinMode == SigninMode.ResumeFromLastGood)
                {
                    signinMode = SigninMode.NewSign;
                    propmtString = UserOpration.Instance.ReLogin();
                }
                else
                {
                    var instance = UserOpration.NewInstance();
                    foreach (ToolStripMenuItem i in Proxy_toolStripMenuItem.DropDownItems)
                    {
                        if (i.Checked)
                        {
                            instance.ProxyName = i.Text;
                        }
                    }

                    propmtString = instance.Login(captchaHandle, user, pwd);
                }

                if (!this.IsDisposed && InvokeRequired)
                    this.Invoke(loginComplete, propmtString);

            });

            waitInputThread.SetApartmentState(ApartmentState.STA);
            waitInputThread.Start();

        }

        private void txt_userToStation_QueryStStrainAll(object sender, EventArgs e)
        {
            if (txt_userToStation.SelectedIndex < 0 ||
                txt_userFromStation.SelectedIndex < 0 ||
                string.IsNullOrEmpty(txt_userToStation.Text) ||
                string.IsNullOrEmpty(txt_userFromStation.Text))
                return;

            if (txt_dateTimePicker.Value <= DateTime.Today)
            {
                Log.Error("日期需要大于今日. ");
                return;
            }

            Log.Debug("start:search trains.");

            txt_userTrains.Items.Clear();
            txt_userTrains.Enabled = false;

            string day = txt_dateTimePicker.Value.ToString("yyyy-MM-dd");

            //first one is initial letter for index
            string fromText = txt_userFromStation.Text.Split(',')[1];
            string toText = txt_userToStation.Text.Split(',')[1];

            //already in dropdown so index won't be out of bound.
            string fromCode = FindCodeByChineseName(fromText);
            string toCode = FindCodeByChineseName(toText);

            if (fromCode == toCode) return;

            if (txt_userFromStation.SelectedIndex < 0 || txt_userToStation.SelectedIndex < 0)
            {
                txt_userTrains.Enabled = false;
                return;
            }

            SetWorkStatus(true);

            UpdateFormControlDelegate initializeTrainListThreadDelegate = new UpdateFormControlDelegate(arg =>
            {
                try
                {
                    Log.Debug("start:set data to controls for seat types.");

                    Comparison<JsonObject> compareDelegate = delegate(JsonObject x, JsonObject y)
                    {
                        if (x.value[0] == y.value[0])
                        { return 0; }

                        int result = x.value[0] > y.value[0] ? -1 : 1;
                        return result;
                    };


                    List<object> extraNames = new List<object>();
                    List<JsonObject> source = arg as List<JsonObject>;
                    source.Sort(compareDelegate);

                    foreach (JsonObject item in source)
                    {
                        if (item.end_station_name == toText) //put exact match to the beginning and put the rest to end 
                            txt_userTrains.Items.Add(item.value);
                        else
                            extraNames.Add(item.value);
                    }


                    txt_userTrains.Items.AddRange(extraNames.ToArray<object>());


                    if (txt_userTrains.Items.Count > 0)
                    {
                        txt_userTrains.Enabled = true;
                        if (txt_userTrains.Items.Contains(Configurations.Instance.txt_userTrains))
                        {
                            txt_userTrains.SelectedItem = Configurations.Instance.txt_userTrains;
                        }
                        else
                            txt_userTrains.SelectedIndex = 0;

                        Log.Debug("end:retrieve train list is complete.");
                        txt_userTrains.Focus();
                    }
                    else
                    {
                        Log.Error("[{0}] 到 [{1}] 车次信息暂无。", fromText, toText);
                    }
                }
                catch (Exception ex)
                {
                    Log.Debug(ex.ToString());
                }
                finally
                {
                    SetWorkStatus(false);
                }
            });

            Thread thPrep = new Thread(() =>
            {
                if (threadMutex.WaitOne(TimeSpan.Zero))
                {
                    try
                    {
                        object stationData = UserOpration.Instance.QueryStStrainAll(day, fromCode, toCode);

                        if (!this.IsDisposed)
                            this.Invoke(initializeTrainListThreadDelegate, stationData);
                    }
                    finally
                    {
                        threadMutex.ReleaseMutex();
                    }
                }
                else
                {
                    Log.Debug("Thread is busy, job of this thread is aborted. from {0} to {1}", fromText, toText);
                }

            });

            thPrep.SetApartmentState(ApartmentState.STA);
            thPrep.Start();

        }

        /// <summary>
        /// get train info by id. 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txt_userTrains_QueryLeftTickets(object sender, EventArgs e)
        {
            UpdateFormControlDelegate del = new UpdateFormControlDelegate(
                par =>
                {
                    if (txt_dateTimePicker.Value <= DateTime.Today)
                    {
                        Log.Error("日期需要大于今日. ");
                        return;
                    }

                    lst_trainDetail.Items.Clear();

                    if (txt_userTrains.SelectedIndex < 0)
                    {
                        this.lst_trainDetail.Tag = null;
                        return;
                    }
                    Log.Debug("start:query left tickets");


                    string trainId = txt_userTrains.SelectedItem.ToString();
                    var train = Global.TrainCodeList.Find(t => t.value == trainId);

                    if (train == null)
                    {
                        this.lst_trainDetail.Tag = null;
                        return;
                    }

                    try
                    {
                        SetWorkStatus(true);
                        //query left ticket
                        string day = txt_dateTimePicker.Value.ToString("yyyy-MM-dd");
                        string fromText = txt_userFromStation.Text.Split(',')[1];
                        string toText = txt_userToStation.Text.Split(',')[1];
                        string from = FindCodeByChineseName(fromText);
                        string to = FindCodeByChineseName(toText);

                        //station chinese name to code after output
                        var resultList = UserOpration.Instance.QueryLeftTicket(day, from, to, fromText, toText);
                        Log.Debug("end: query left ticket, attach object data to tag.");

                        UpdateQueryleftTicket(resultList, trainId);

                    }
                    catch (Exception ex)
                    {
                        Log.Debug(ex.ToString());
                    }
                    finally
                    { SetWorkStatus(false); }

                });

            if (this.InvokeRequired)
                this.Invoke(del, "");
            else
                del("");
        }


        private void UpdateQueryleftTicket(List<OrderData> resultList, string trainId)
        {
            UpdateFormControlDelegate del = new UpdateFormControlDelegate(
                par =>
                {
                    lst_trainDetail.Items.Clear();
                    menu_status.Text = "Last update " + DateTime.Now.ToString("T");
                    if (resultList == null || resultList.Count == 0)
                    {
                        return;
                    }

                    ListViewItem selectedItem = null;
                    foreach (OrderData data in resultList)
                    {
                        ListViewItem item = new ListViewItem(data.station_train_code);
                        item.Name = data.station_train_code;
                        item.Tag = data.Status;
                        item.SubItems.Add(data.HasTicket ? "有" : data.Status);
                        item.SubItems.Add(data.train_start_time);
                        item.SubItems.Add(data.arrive_time);

                        //could be D33/D32
                        if (trainId.Contains(data.station_train_code))
                        {
                            Log.Message("{0} [{1}]", data.station_train_code, data.Status);
                            selectedItem = item;
                            this.lst_trainDetail.Tag = data;
                        }
                        else
                        {
                            lst_trainDetail.Items.Add(item);
                        }
                    }
                    if (selectedItem != null)
                    {
                        lst_trainDetail.Items.Insert(0, selectedItem);
                    }

                });

            this.Invoke(del, "");

        }

        private void menu_start_Click(object sender, EventArgs e)
        {
            Log.Debug("start:timer enabled for search.");
            Global.SeatTypeTargets = new List<JsonObject>();
            UserOpration.CancelState = false;
            foreach (var checkeditem in chk_userSeatTypes.CheckedItems)
            {
                JsonObject obj = null;
                if (
                    (obj = Global.TicketCodeList.Find(j => j.value == checkeditem.ToString()))
                    != null)
                {
                    Global.SeatTypeTargets.Add(obj);
                    continue;
                }
            }

            if (Global.SeatTypeTargets.Count == 0)
            {
                MessageBox.Show("需要选择票类型", "Error");
                return;
            }
            if (lst_trainDetail.Tag == null)
            {
                MessageBox.Show("需要选择一个列车, 等待加载或选择。", "Error");
                return;
            }

            SetWorkStatus(true);

            mainWorkThread = new Thread(new ParameterizedThreadStart(backgroundWorker1_DoWork));
            mainWorkThread.SetApartmentState(ApartmentState.STA);
            mainWorkThread.Start(passengers);

            //this.backgroundWorker1.RunWorkerAsync(passengers);
        }

        private void menu_cancel_Click(object sender, EventArgs e)
        {
            Log.Error("稍后， 正在取消任务。 ");
            try
            {
                UserOpration.Instance.Abort();

                if (mainWorkThread != null && mainWorkThread.IsAlive)
                {
                    mainWorkThread.Abort();
                }
            }
            catch (Exception exc)
            {
                Log.Debug(exc.Message);
            }
            finally
            {
                MainThreadEnded();
            }
        }

        //uninstall
        private void menu_ExtraAction_Click(object sender, EventArgs e)
        {
            Program.Register(string.Empty, true);

            ShowToolTip("Uninstall", "已经卸载。下次打开页面时不会加载。重新启用点击 .exe 文件开始。");
        }


        void backgroundWorker1_DoWork(object argument)
        {
            //BackgroundWorker worker = sender as BackgroundWorker;
            OrderData odata = lst_trainDetail.Tag as OrderData;
            List<UserData> user = argument as List<UserData>;


            Log.Message("开始运行， 查询超时约{1}分钟后停止, 点击 {0} 可以立刻停止。", menu_cancel.Text, WORKER_TIMEOUT_MINUTES);


            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            watch.Start();
            bool result = false;
            while (watch.Elapsed.TotalMinutes < WORKER_TIMEOUT_MINUTES)
            {
                var infoArray = UserOpration.Instance.QueryLeftTicket(odata.train_date,
                        odata.from_station_telecode,
                        odata.to_station_telecode,
                        odata.from_station_telecode_name,
                        odata.to_station_telecode_name);
                UpdateQueryleftTicket(infoArray, odata.station_train_code);

                if (odata.HasTicket)
                {
                    ShowToolTip("QueryleftTicket", "Stopped.");
                    result = true;
                    break;
                }
                Thread.Sleep(1000);


                int percent = (int)(100 * watch.Elapsed.TotalMinutes / WORKER_TIMEOUT_MINUTES);
                percent = percent < 30 ? 30 : percent; //for virsual effort set to 30%
            }

            if (result == false)
            {
                Log.Error("车次信息不可用， 停止提交。 ");
                return;
            }

            int validPassengerId = 1;
            //validate passenger info
            for (int idx = 0; idx < passengers.Count; idx++)
            {
                var passengerData = passengers[idx];
                if (string.IsNullOrEmpty(passengerData.passenger_1_name) ||
                    string.IsNullOrEmpty(passengerData.passenger_1_cardno) ||
                    string.IsNullOrEmpty(passengerData.passenger_1_mobileno))
                    passengerData.PassengerId = -1;
                else
                {
                    passengerData.PassengerId = validPassengerId++;
                }
            }

            try
            {
                //for (int t = 1; t < 10; t++)
                //{
                //    CheckThreadStateToAbort();

                //    Log.Message("第 {0} 次提交。", t);
                //    string err = UserOpration.Instance.SubmitOrderRequest(odata, user, captchaHandle);
                //    if (!string.IsNullOrEmpty(err))
                //        break;
                //}
            }
            catch (InvalidOperationException iex)
            {
                Log.Debug("Canceled dues to {0}", iex.Message);
            }
            finally
            {
                MainThreadEnded();
            }
        }

        private void MainThreadEnded()
        {
            this.Invoke(new UpdateFormControlDelegate(a =>
                {
                    win7SuperIcon.SetState(this.Handle, TBPFLAG.TBPF_NOPROGRESS);
                    Log.Message("##运行已经停止。##");
                    SetWorkStatus(false);
                    ShowToolTip("12306", "运行已经停止。");
                }),
                "");
        }


        protected override void OnClosing(CancelEventArgs e)
        {
            if (!string.IsNullOrEmpty(txt_userFromStation.Text))
                Configurations.Instance.txt_userFromStation = txt_userFromStation.Text.ToString();
            if (!string.IsNullOrEmpty(txt_userToStation.Text))
                Configurations.Instance.txt_userToStation = txt_userToStation.Text.ToString();
            if (!string.IsNullOrEmpty(txt_userTrains.Text))
                Configurations.Instance.txt_userTrains = txt_userTrains.Text.ToString();

            if (!string.IsNullOrEmpty(txt_userWebName.Text))
                Configurations.Instance.WebUserName = txt_userWebName.Text.ToString();
            if (!string.IsNullOrEmpty(txt_userWebPassword.Text))
                Configurations.Instance.WebUserPassword = txt_userWebPassword.Text.ToString();


            Configurations.Instance.Save();


            if (backgroundWorker1.IsBusy)
                menu_cancel_Click(menu_cancel, null);

            base.OnClosing(e);

            listen.Dispose();
            this.Dispose();
        }


        #region private func
        private void ShowToolTip(string caption, string text)
        {
            notifyIcon1.Visible = true;
            notifyIcon1.ShowBalloonTip(10000, caption, text, ToolTipIcon.Warning);

        }


        private void SetWorkStatus(bool isworking = true)
        {
            menu_status.Text = isworking ? "正在查询" : "Ready";
            menu_start.Enabled = !isworking;
            group_login.Enabled = !isworking;
            group_webform.Enabled = !isworking;
            group_ticket.Enabled = !isworking;

            menu_cancel.Enabled = isworking;

            if (!isworking)
            {
                user_imageBox.Image = null;
                lbl_userCaptchaInfo.Text = string.Empty;
                txt_webCaptcha.Text = string.Empty;
            }
        }

        private void InitializeControlsFromSetting()
        {
            this.StartPosition = FormStartPosition.Manual;
            this.Location = new Point(0, 0);
            //only create listener window after main form is visible, if not, the bho counter will detect more than 1 window in sington mode.
            this.Shown += (object sender, EventArgs e) => { listen = new ListenerWindow(); };

            this.Icon = Icon.ExtractAssociatedIcon(Environment.ExpandEnvironmentVariables("%ProgramFiles%" + @"\Internet Explorer\iexplore.exe"));
            this.notifyIcon1.Icon = this.Icon;
            this.notifyIcon1.Visible = false;
            this.notifyIcon1.Text = "12306";
            this.notifyIcon1.BalloonTipClosed += (object sender, EventArgs e) => { notifyIcon1.Visible = false; };
            this.notifyIcon1.BalloonTipClicked += (object sender, EventArgs e) => { SetForegroundWindow(this.Handle); };

            //1 means include today.
            txt_dateTimePicker.Value = DateTime.Today.Add(new TimeSpan(ORDER_DAY_AHEAD - 1, 0, 0, 0));
            chk_userSeatTypes.Items.AddRange(Configurations.Instance.chk_userSeatTypes.Split(','));
            Log.Add(new FormLog(this.txt_log));


            foreach (string p in Configurations.Instance.ProxyList)
            {

                ToolStripMenuItem menuItem = new ToolStripMenuItem(p);
                menuItem.Click += (object sender, EventArgs e) =>
                {
                    foreach (ToolStripMenuItem i in Proxy_toolStripMenuItem.DropDownItems)
                    {
                        i.CheckState = CheckState.Unchecked;
                    }

                    ToolStripMenuItem item = sender as ToolStripMenuItem;
                    item.CheckState = CheckState.Checked;

                    UserOpration.Instance.ProxyName = item.Text;
                };

                Proxy_toolStripMenuItem.DropDownItems.Add(menuItem);
            }




            KeyPressEventHandler submitHandler = delegate(object sender, KeyPressEventArgs e)
            {
                if (e.KeyChar == (char)Keys.Enter)
                {
                    btn_login_Click(btn_login, EventArgs.Empty);
                    e.Handled = true;
                }
            };
            txt_userWebName.KeyPress += submitHandler;
            txt_userWebPassword.KeyPress += submitHandler;

            for (int i = 0; i < 5; i++)
            {
                string[] data = null;

                try
                {
                    data = Configurations.Instance.PassengerList[i].Split(',');
                }
                catch (Exception)
                {
                    data = new string[3];
                }

                passengers.Add(new UserData(i) { passenger_1_name = data[0], passenger_1_cardno = data[1], passenger_1_mobileno = data[2] });
            }
        }



        private void InitializeCaptchaDelegate()
        {
            UpdateFormControlDelegate updateImage = new UpdateFormControlDelegate(arg =>
            {
                this.WindowState = FormWindowState.Normal;
                this.Activate();
                SetForegroundWindow(this.Handle);

                txt_webCaptcha.Focus();
                user_imageBox.Image = arg as Image;
                lbl_userCaptchaInfo.Text = "60秒内输入验证码。";
            });

            UpdateFormControlDelegate clearCaptchaCode = new UpdateFormControlDelegate(arg =>
            {

                txt_webCaptcha.Text = string.Empty;
                user_imageBox.Image = null;
                lbl_userCaptchaInfo.Text = string.Empty;
            });

            captchaHandle = (img) =>
            {
                if (img == null)
                {
                    Log.Error("出现错误， 不能获取验证码。 ");
                    return string.Empty;
                }

                ImageUtil.GrayImage(ref img);

                if (!this.IsDisposed)
                    this.Invoke(updateImage, img);

                Log.Error("!!!!!!!!! 输入验证码 !!!!!!!!!!!");
                int i = 0;
                while (i++ < 20)
                {
                    CheckThreadStateToAbort();
                    Thread.Sleep(2000);
                    if (txt_webCaptcha.Text.Length == 4)
                        break;
                }

                string ret = txt_webCaptcha.Text;

                if (!this.IsDisposed)
                    this.Invoke(clearCaptchaCode, "");
                return ret;
            };
        }

        private string FindCodeByChineseName(string name)
        {
            var rows = Global.StationNameTable.Select(string.Format("{0}='{1}'", Global.DataComlumnChineseName, name));
            string code = rows[0][Global.DataComlumnCodeName] as string;

            return code;
        }

        private void CheckThreadStateToAbort()
        {
            //dispose in OnClosing event, then send thread abort signal
            if (!this.IsDisposed)
            {
                UserOpration.CheckThreadStateToAbort();
            }
        }

        #endregion

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start(linkLabel1.Text);
        }

        private void btn_showPassengers_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy)
            {
                return;
            }

            PassengerInfoForm pi = new PassengerInfoForm(passengers);
            pi.ShowDialog(this);
        }

        private void menu_proxyTest_Click(object sender, EventArgs e)
        {
            WebProxyTest test = new WebProxyTest();
            test.ShowDialog(this);
        }

        private void menu_login_Click(object sender, EventArgs e)
        {
            group_login.Visible = menu_login.Checked;
            menu_login.Checked = !menu_login.Checked;
        }

        private void lst_trainDetail_MouseClick(object sender, MouseEventArgs e)
        {
            if (lst_trainDetail.SelectedItems.Count > 0)
            {
                var item = lst_trainDetail.SelectedItems[0];
                if (item.Tag != null)
                {
                    Log.Message("{0}, {1}", item.Name, item.Tag.ToString());
                }
            }
        }

    }


    internal class ListenerWindow : NativeWindow, IDisposable
    {
        int WS_DISABLED = 0x8000000;
        public ListenerWindow()
            : base()
        {
            CreateParams cp = new CreateParams();
            //cp.Parent = hwnd;
            cp.Caption = MainForm.FORM_UNIQUE_Name;

            cp.X = 0;
            cp.Y = 0;
            cp.Height = 0;
            cp.Width = 0;
            cp.Style = WS_DISABLED;

            CreateHandle(cp);
        }



        public void Dispose()
        {
            this.DestroyHandle();
            this.ReleaseHandle();

        }
    }
}
